package com.yanyeori.webtest.controller;

import cn.hutool.core.net.URLEncodeUtil;
import cn.zhxu.data.TypeRef;
import cn.zhxu.okhttps.HTTP;
import cn.zhxu.okhttps.jackson.JacksonMsgConvertor;
import com.alibaba.excel.EasyExcel;
import com.fasterxml.jackson.core.type.TypeReference;
import com.yanyeori.framework.core.context.TraceContext;
import com.yanyeori.framework.core.context.UserContext;
import com.yanyeori.framework.core.model.WebResponse;
import com.yanyeori.framework.core.util.HttpUtil;
import com.yanyeori.framework.core.util.JacksonUtil;
import com.yanyeori.framework.i18n.util.I18nUtil;
import com.yanyeori.framework.redis.util.RedisUtil;
import com.yanyeori.framework.security.annotation.Anonymous;
import com.yanyeori.framework.security.entity.User;
import com.yanyeori.framework.web.http.request.okhttp.OkHttpRequestInterceptor;
import com.yanyeori.framework.websocket.server.WebSocketUtil;
import com.yanyeori.nacosfeign.client.FeignAClient;
import com.yanyeori.nacosfeign.context.AContext;
import com.yanyeori.nacosfeign.context.AContextHolder;
import com.yanyeori.webtest.bo.ExcelBO;
import com.yanyeori.webtest.bo.LoginLogBO;
import com.yanyeori.webtest.constant.WebConst;
import com.yanyeori.webtest.entity.clear.BankEntity;
import com.yanyeori.webtest.service.BankService;
import com.yanyeori.webtest.service.LoginLogService;
import com.yanyeori.webtest.service.TestDataService;
import com.yanyeori.webtest.service.UserService;
import com.yanyeori.webtest.service.impl.redistest.ListenerTest1;
import com.yanyeori.webtest.service.impl.redistest.ListenerTest2;
import com.yanyeori.webtest.service.impl.redistest.PublishTest;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 测试接口
 *
 * @author chenkuan 2020/8/07
 */
@Slf4j
@Api(tags = "测试Web服务")
@RestController
@RequestMapping("/testController")
public class TestController {

    @Autowired
    private BankService bankService;
    @Autowired
    private UserService userService;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private PublishTest publishTest;
    @Autowired
    private FeignAClient feignAClient;
    @Autowired
    private RestTemplate restTemplate;
    @Resource(name = WebConst.RESTTEMPLATE_LOADBALANCED)
    private RestTemplate restTemplateLoadBalanced;
    @Autowired
    private LoginLogService loginLogService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private TestDataService testDataService;

    @ApiOperation("分页查询银行列表")
    @GetMapping("/listBank")
    public WebResponse<?> listBank() {
        return bankService.pageBank();
    }

    @ApiOperation("通过银行代码查询银行信息")
    @GetMapping("/getByBankId")
    public WebResponse<BankEntity> getByBankId(@ApiParam(value = "银行代码", required = true) @RequestParam String bankId) {
        log.info("traceId: {}", TraceContext.get(false).getTraceId());
        return bankService.getByBankId(bankId).message(I18nUtil.getMessage("key", "参数"));
    }

    @ApiOperation("插入银行信息")
    @PostMapping("/saveBank")
    public WebResponse<?> saveBank(@RequestBody @Valid BankEntity bank) {
        return bankService.saveBank(bank);
    }

    @PostMapping("/updateBank")
    public WebResponse<?> updateBank(@RequestParam String isError) {
        return bankService.updateBank(isError);
    }

    @GetMapping("/listUser")
    public WebResponse<List<User>> listUser() {
        return userService.list();
    }

    @PostMapping("/setBankRedis")
    public WebResponse<?> setBankRedis(@RequestParam String key) {
        List<BankEntity> bankList = bankService.listBank();
        boolean result = redisUtil.set(key, bankList);
        return WebResponse.ok(result);
    }

    @PostMapping("/getBankRedis")
    public WebResponse<?> getBankRedis(@RequestParam String key) {
        List<BankEntity> value = redisUtil.get(key);
        return WebResponse.ok(value);
    }

    @PostMapping("/delRedis")
    public WebResponse<?> delRedis(@RequestParam String key) {
        redisUtil.del(key);
        return WebResponse.ok();
    }

    @PostMapping("/setRedis1")
    public WebResponse<?> setRedis1(@RequestParam String key, @RequestParam String hashKey) {
        List<BankEntity> bankList = bankService.listBank();
        Map<String, List<BankEntity>> map = new HashMap<>();
        map.put(hashKey, bankList);
        boolean result = redisUtil.hmSet(key, map);
        return WebResponse.ok(result);
    }

    @PostMapping("/setRedis2")
    public WebResponse<?> setRedis2(@RequestParam String key, @RequestParam String hashKey) {
        BankEntity bank = new BankEntity();
        bank.setBankId("myBankId");
        List<BankEntity> banks = new ArrayList<>();
        banks.add(bank);
        boolean result = redisUtil.hSet(key, hashKey, banks);
        return WebResponse.ok(result);
    }

    @PostMapping("/getRedis1")
    public WebResponse<?> getRedis1(@RequestParam String key) {
        Map<String, List<BankEntity>> result = redisUtil.hmGet(key);
        return WebResponse.ok(result);
    }

    @PostMapping("/getRedis2")
    public WebResponse<?> getRedis2(@RequestParam String key, @RequestParam String hashKey) {
        List<BankEntity> result = redisUtil.hGet(key, hashKey);
        return WebResponse.ok(result);
    }

    @Anonymous
    @PostMapping("/pushRedis1")
    public WebResponse<?> pushRedis1() {
        BankEntity bank = bankService.listBank().get(0);
        redisUtil.push(ListenerTest1.topic, bank);
        return WebResponse.ok();
    }

    @Anonymous
    @PostMapping("/pushRedis2")
    public WebResponse<?> pushRedis2() {
        List<BankEntity> bankList = bankService.listBank();
        redisUtil.push(ListenerTest2.topic, bankList);
        return WebResponse.ok();
    }

    @PostMapping("/publishTest")
    public WebResponse<?> publishTest(@RequestParam boolean isRemote) {
        publishTest.publishEvent(isRemote);
        return WebResponse.ok();
    }

    @PostMapping("/sendWebsocket")
    public void sendWebsocket(@RequestParam String topic, @RequestParam String message) throws IOException {
        WebSocketUtil.send(message, topic);
    }

    @Anonymous
    @PostMapping("/feignToA")
    public void feignToA() throws UnknownHostException {
        log.info("traceId: {}", TraceContext.get(true).getTraceId());

        AContext aContext = new AContext();
        aContext.setIp(Inet4Address.getLocalHost().getHostAddress());
        aContext.setUserId("kuan");
        aContext.setName("chenkuan");
        aContext.setAge(18);
        AContextHolder.setAContext(aContext);

        log.debug("web-test调用测试, {}", UserContext.get());
        feignAClient.rest("web-test feign 调用测试");

        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("param", "web-test restTemplate 调用测试");
        restTemplate.postForObject(HttpUtil.buildUrlParams("http://127.0.0.1:8033/testController/rest", map), null, WebResponse.class);

        map.clear();
        map.add("param", "web-test restTemplateLoadBalanced 调用测试");
        restTemplateLoadBalanced.postForObject(HttpUtil.buildUrlParams("http://nacos-feign-a-business/testController/rest", map), null, WebResponse.class);

        HttpUtil httpUtil = HttpUtil
                .builder()
                .setRestTemplate(restTemplate)
                .setBaseUrl("http://127.0.0.1:8033")
                .build();
        WebResponse<String> result = httpUtil
                .http("/testController/rest")
                .setUrlParams("param", "web-test HttpUtil 调用测试")
                .post()
                .toBean(new TypeReference<WebResponse<String>>() {
                });

        HTTP okHttp = HTTP.builder()
                .config(builder -> {
                    builder.addInterceptor(new OkHttpRequestInterceptor());
                })
                .addMsgConvertor(new JacksonMsgConvertor())
                .build();
        WebResponse<String> response = okHttp
                .sync("http://127.0.0.1:8033/testController/rest")
                .bodyType(MediaType.APPLICATION_JSON_VALUE)
                .addUrlPara("param", "web-test OkHttps 调用测试")
                .post()
                .getBody()
                .toBean(new TypeRef<WebResponse<String>>() {
                });

        log.debug("web-test调用测试-结束");
    }

    @Anonymous
    @PostMapping("/listLoginLog")
    public WebResponse<List<LoginLogBO>> listLoginLog(@RequestBody LoginLogBO loginLogBO) {
        List<LoginLogBO> list = loginLogService.listLoginLog(loginLogBO);
        return WebResponse.ok(list);
    }

    @Anonymous
    @PostMapping("/upload/test")
    public WebResponse<?> uploadTest(@RequestPart MultipartFile file) throws IOException {
        List<ExcelBO> list = EasyExcel.read(file.getInputStream()).sheet().head(ExcelBO.class).headRowNumber(1).doReadSync();
        log.info(JacksonUtil.toJson(list));
        return WebResponse.ok();
    }

    @Anonymous
    @PostMapping("/download/test")
    public void downloadTest(HttpServletResponse response) throws IOException {
        List<ExcelBO> list = new ArrayList<>();
        list.add(new ExcelBO("一1231123"));
        list.add(new ExcelBO("ersdfdve3"));
        setDownloadHeader(response, "测试文件.xlsx");
        EasyExcel.write(response.getOutputStream()).sheet().head(ExcelBO.class).doWrite(list);
    }

    private void setDownloadHeader(HttpServletResponse response, String filename) {
        response.setContentType("application/octet-stream;charset=UTF-8");
        response.setHeader("Content-Disposition", String.format("attachment;filename=%s", URLEncodeUtil.encode(filename)));
    }

    @PostMapping("/saveBatch")
    public WebResponse<?> saveBatch(Integer size) {
        testDataService.saveBatch(size);
        return WebResponse.ok();
    }

    @PostMapping("/insertBatch")
    public WebResponse<?> insertBatch(Integer size) {
        testDataService.insertBatch(size);
        return WebResponse.ok();
    }
}
